package com.franklin.validation.core.argument.resolvers;

import com.franklin.validation.core.annotations.ParamCheck;
import com.franklin.validation.core.annotations.WebFluxFormDataComponent;
import com.franklin.validation.core.argument.impl.ResultFactoryImpl;
import com.franklin.validation.core.argument.interfaces.ResultFactory;
import com.franklin.validation.core.cache.RequestMultiValueCache;
import com.franklin.validation.core.constants.Constants;
import com.franklin.validation.core.entity.CheckFormEntity;
import com.franklin.validation.core.entity.CheckResult;
import com.franklin.validation.core.exception.ParamCheckException;
import com.franklin.validation.core.utils.DataCheckUtil;
import com.franklin.validation.core.utils.ReflectionUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpHeaders;
import org.springframework.web.reactive.BindingContext;
import org.springframework.web.reactive.result.method.HandlerMethodArgumentResolver;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl;

import javax.annotation.PostConstruct;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * Description :
 * Create By: Franklin
 * Date : 2020/6/15 16:49
 */
@WebFluxFormDataComponent
public class ParamCheckHandlerArgumentResolverV2 implements HandlerMethodArgumentResolver {

    private List<String> emptyList;

    @Autowired
    private ResultFactoryImpl resultFactory;
    @Autowired
    private RequestMultiValueCache<String,String> cache;

    @PostConstruct
    public void init(){
        this.emptyList = new ArrayList<>(0);
    }

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.hasParameterAnnotation(ParamCheck.class);
    }

    @Override
    public Mono<Object> resolveArgument(MethodParameter methodParameter, BindingContext bindingContext, ServerWebExchange serverWebExchange) {
        Class<?> returnType = methodParameter.getMethod().getReturnType();
        HttpHeaders headers = serverWebExchange.getRequest().getHeaders();
        String requestId = headers.get(Constants.REQUEST_ID).get(0);
        ParamCheck paramCheck = methodParameter.getParameterAnnotation(ParamCheck.class);
//            Map<String, List<String>> params = ParamsCache.getParams(requestId);
        Map<String, List<String>> params = this.cache.getParams(requestId);
        List<String> values = DataCheckUtil.isEmpty(params) ? this.emptyList : params.get(paramCheck.value());
        Class<?> parameterType = methodParameter.getParameterType();
        Type genericParameterType = methodParameter.getGenericParameterType();
        Class<?> genericType = null;
        if (genericParameterType instanceof ParameterizedTypeImpl){
            ParameterizedTypeImpl genericParameterType1 = (ParameterizedTypeImpl) genericParameterType;
            Type[] actualTypeArguments = genericParameterType1.getActualTypeArguments();
            genericType = (Class<?>)actualTypeArguments[0];
        }
//        Class.forName()
        if (paramCheck.type() == Date.class){
            parameterType = Date.class;
        }
        CheckFormEntity checkFormEntity = new CheckFormEntity(values,parameterType,paramCheck,genericType);
        CheckResult checkResult = this.resultFactory.check(checkFormEntity);
        if (checkResult.isSuccess()){
            Object result = this.resultFactory.getResult(checkFormEntity);
            return Mono.just(result);
        }
        boolean isSysDefault = ReflectionUtil.isSystemDefaultValue(paramCheck.defaultValue());
        if (paramCheck.required()){
            //必填
            if (isSysDefault){
                throw new ParamCheckException(checkResult.getMessage());
            }
        }
        Object onError = this.resultFactory.onError(checkFormEntity);
        return Mono.just(onError);
    }
}
